﻿using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;

namespace BSF.Ioc
{
    public class FolderAssemblyFinder : IAssemblyFinder
    {
        private static readonly string DEFAULT_IGNORE_PATTERN
              = "^System|^mscorlib|^Microsoft|^CppCodeProvider|^VJSharpCodeProvider|^WebDev|^Castle|^Iesi|^log4net|^NHibernate|^nunit|^TestDriven|^MbUnit|^Rhino|^QuickGraph|^TestFu|^Telerik|^ComponentArt|^MvcContrib|^AjaxControlToolkit|^Antlr3|^Remotion|^Recaptcha|^Spire|^Aspose|^Interop.";
        public string FolderPath { get; private set; }

        public SearchOption SearchOption { get; private set; }

        private List<Assembly> _assemblies;

        private readonly object _syncLock = new object();

        public FolderAssemblyFinder(string folderPath, SearchOption searchOption = SearchOption.TopDirectoryOnly)
        {
            FolderPath = folderPath;
            SearchOption = searchOption;
        }

        public List<Assembly> GetAllAssemblies()
        {
            if (_assemblies == null)
            {
                lock (_syncLock)
                {
                    if (_assemblies == null)
                    {
                        _assemblies = GetAllAssembliesInternal();
                    }
                }
            }

            return _assemblies;
        }

        private List<Assembly> GetAllAssembliesInternal()
        {
            var assemblies = new List<Assembly>();
            var dllFiles = Directory.GetFiles(FolderPath, "*.dll", SearchOption);

            foreach (string dllFile in dllFiles)
            {
                var isIgnore = Matches(dllFile, DEFAULT_IGNORE_PATTERN);
                if (isIgnore) continue;

                assemblies.Add(Assembly.LoadFile(dllFile));
            }

            return assemblies;
        }

        protected virtual bool Matches(string assemblyFullName, string pattern)
        {
            var fileName = System.IO.Path.GetFileNameWithoutExtension(assemblyFullName);
            return Regex.IsMatch(fileName, pattern
                , RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }
    }
}
